package org.buildoop.storm;
import backtype.storm.Config;
import backtype.storm.LocalCluster;
import backtype.storm.StormSubmitter;
import backtype.storm.generated.AlreadyAliveException;
import backtype.storm.generated.InvalidTopologyException;
import backtype.storm.generated.StormTopology;
import backtype.storm.spout.SchemeAsMultiScheme;
import backtype.storm.topology.TopologyBuilder;
import backtype.storm.tuple.Fields;
import backtype.storm.tuple.Tuple;
import org.apache.storm.hbase.bolt.mapper.SimpleHBaseMapper;
import org.apache.storm.hbase.bolt.HBaseBolt;
import org.buildoop.storm.bolts.AuditParserBolt;
import org.buildoop.storm.bolts.AuditLoginsCounterBolt;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import storm.kafka.BrokerHosts;
import storm.kafka.KafkaSpout;
import storm.kafka.SpoutConfig;
import storm.kafka.StringScheme;
import storm.kafka.ZkHosts;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Properties;
import com.hmsonline.storm.contrib.bolt.elasticsearch.ElasticSearchBolt;
import com.hmsonline.storm.contrib.bolt.elasticsearch.mapper.DefaultTupleMapper;
import com.hmsonline.storm.contrib.bolt.elasticsearch.mapper.TupleMapper;
import com.hmsonline.storm.elasticsearch.StormElasticSearchConstants;
public class AuditActiveLoginsTopology {
public static final Logger LOG = LoggerFactory
.getLogger(AuditActiveLoginsTopology.class);
private final BrokerHosts kafkaBrokerHosts;
public AuditActiveLoginsTopology(String zookeeperHosts) {
kafkaBrokerHosts = new ZkHosts(zookeeperHosts);
}
public StormTopology buildTopology(Properties properties) {
// Load properties for the storm topology
String kafkaTopic = properties.getProperty("kafka.topic");
SpoutConfig kafkaConfig = new SpoutConfig(kafkaBrokerHosts, kafkaTopic, "", "storm");
kafkaConfig.scheme = new SchemeAsMultiScheme(new StringScheme());
TopologyBuilder builder = new TopologyBuilder();
// Specific audit logs analysis bolts
AuditLoginsCounterBolt loginCounterbolt = new AuditLoginsCounterBolt();
AuditParserBolt auditParserBolt = new AuditParserBolt();
// Elastic search bolt
TupleMapper tupleMapper = new DefaultTupleMapper();
ElasticSearchBolt elasticSearchBolt = new ElasticSearchBolt(tupleMapper);
// Topology scheme: KafkaSpout -> auditParserBolt -> loginCounterBolt -> elasticSearchBolt
builder.setSpout("KafkaSpout", new KafkaSpout(kafkaConfig), 1);
builder.setBolt("ParseBolt", auditParserBolt, 1).shuffleGrouping("KafkaSpout");
builder.setBolt("CountBolt", loginCounterbolt, 1).shuffleGrouping("ParseBolt");
builder.setBolt("ElasticSearchBolt", elasticSearchBolt, 1)
.fieldsGrouping("CountBolt", new Fields("id", "index", "type", "document"));
return builder.createTopology();
}
private static List<String> parseZkHosts(String zkNodes) {
String[] hostsAndPorts = zkNodes.split(",");
List<String> hosts = new ArrayList<String>(hostsAndPorts.length);
for (int i = 0; i < hostsAndPorts.length; i++) {
hosts.add(i, hostsAndPorts[i].split(":")[0]);
}
return hosts;
}
private static int parseZkPort(String zkNodes) {
String[] hostsAndPorts = zkNodes.split(",");
int port = Integer.parseInt(hostsAndPorts[0].split(":")[1]);
return port;
}
private static Properties loadProperties(String propertiesFile) throws Exception {
Properties properties = new Properties();
FileInputStream in = new FileInputStream(propertiesFile);
properties.load(in);
in.close();
return properties;
}
private static void loadTopologyPropertiesAndSubmit(Properties properties,
Config config) throws Exception {
String stormExecutionMode = properties.getProperty("storm.execution.mode","local");
int stormWorkersNumber = Integer.parseInt(properties.getProperty("storm.workers.number","2"));
int maxTaskParallism = Integer.parseInt(properties.getProperty("storm.max.task.parallelism","2"));
String topologyName = properties.getProperty("storm.topology.name","topologyName");
String zookeeperHosts = properties.getProperty("zookeeper.hosts");
int topologyBatchEmitMillis = Integer.parseInt(
properties.getProperty("storm.topology.batch.interval.miliseconds","2000"));
// How often a batch can be emitted in a Trident topology.
config.put(Config.TOPOLOGY_TRIDENT_BATCH_EMIT_INTERVAL_MILLIS, topologyBatchEmitMillis);
config.setNumWorkers(stormWorkersNumber);
config.setMaxTaskParallelism(maxTaskParallism);
AuditActiveLoginsTopology auditActiveLoginsTopology = new AuditActiveLoginsTopology(zookeeperHosts);
StormTopology stormTopology = auditActiveLoginsTopology.buildTopology(properties);
// Elastic Search specific properties
config.put(StormElasticSearchConstants.ES_HOST, properties.getProperty("elasticsearch.host", "localhost"));
config.put(StormElasticSearchConstants.ES_PORT, (Integer.parseInt(properties.getProperty("elasticsearch.port", "9300"))));
config.put(StormElasticSearchConstants.ES_CLUSTER_NAME, properties.getProperty("elasticsearch.cluster.name"));
config.put("elasticsearch.index", properties.getProperty("elasticsearch.index"));
config.put("elasticsearch.type", properties.getProperty("elasticsearch.type"));
switch (stormExecutionMode){
case ("cluster"):
String nimbusHost = properties.getProperty("storm.nimbus.host","localhost");
String nimbusPort = properties.getProperty("storm.nimbus.port","6627");
config.put(Config.NIMBUS_HOST, nimbusHost);
config.put(Config.NIMBUS_THRIFT_PORT, Integer.parseInt(nimbusPort));
config.put(Config.STORM_ZOOKEEPER_PORT, parseZkPort(zookeeperHosts));
config.put(Config.STORM_ZOOKEEPER_SERVERS, parseZkHosts(zookeeperHosts));
StormSubmitter.submitTopology(topologyName, config, stormTopology);
break;
case ("local"):
default:
int localTimeExecution = Integer.parseInt(properties.getProperty("storm.local.execution.time","20000"));
LocalCluster cluster = new LocalCluster();
cluster.submitTopology(topologyName, config, stormTopology);
Thread.sleep(localTimeExecution);
cluster.killTopology(topologyName);
cluster.shutdown();
System.exit(0);
}
}
public static void main(String[] args) throws Exception {
String propertiesFile = args[0];
Properties properties = loadProperties(propertiesFile);
Config config = new Config();
loadTopologyPropertiesAndSubmit(properties,config);
}
}